#ifndef THREADPOOL_TPLAST_H
#define THREADPOOL_TPLAST_H

#include <atomic>
#include <condition_variable>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

enum class PoolMode { fixed, cached };
class Thread {
    using ThreadCB = std::function<void(int)>;
    inline static int generateId = 0;
    int threadId;
    ThreadCB func;

   public:
    Thread(ThreadCB func, int id = generateId++);
    ~Thread() = default;
    inline int getThreadId() { return threadId; }
    void Start();
};

class ThreadPool {
public:
    ThreadPool();
    ThreadPool(const ThreadPool&) = delete;
    void ResetMode(PoolMode mode);
    ThreadPool& operator=(const ThreadPool&) = delete;
    ~ThreadPool();
    void Start(unsigned int size = std::thread::hardware_concurrency());
    using Task = std::function<void()>;
    template <typename Fun, typename... Args>
    auto submitTask(Fun&& fun, Args&&... args)
        -> std::future<decltype(fun(args...))>;

private:
    void ThreadTask(int threadId);
    void AddThread();
    void DeleteThread(int threadId);

private:
    PoolMode mode = PoolMode::fixed;
    std::atomic_bool isRunning = false;
    using uint = unsigned int;
    std::vector<std::unique_ptr<Thread>> threads;
    // 在cached模式下，线程池会根据当前任务的数量动态的调整线程池中的个数
    uint initSize = 4;
    uint maxSize = 100;
    std::atomic_uint curThreadSize = 0;
    // 执行任务时，空闲线程加一，执行结束后减一
    std::atomic_uint idleThreadSize = 0;

    std::atomic_uint taskSize = 0;
    uint maxTaskSize = 100;
    std::queue<Task> tasks;

    std::condition_variable notFull;
    std::condition_variable notEmpty;
    std::condition_variable exitCon;
    std::mutex mtx;
};

template <typename Fun, typename... Args>
auto ThreadPool::submitTask(Fun&& fun, Args&&... args)
    -> std::future<decltype(fun(args...))> {
    using namespace std;
    using RType = decltype(fun(args...));
    auto lastTime = std::chrono::high_resolution_clock::now();
    unique_lock<mutex> lock(mtx);
    auto task = make_shared<packaged_task<RType()>>(
        bind(forward<Fun>(fun), forward<Args>(args)...));
    bool f = notFull.wait_for(lock, chrono::seconds(1), [this]() -> bool {
        return taskSize < maxTaskSize;
    });
    // 提交任务超时
    if (!f) {
        std::cerr << "submit task timeout" << endl;
        auto t = make_shared<packaged_task<RType()>>([]() {
            // if (typeid(RType)==typeid(void)) {
            //     return;
            // }
            return; 
        });
        (*t)();
        return t->get_future();
    }
    tasks.push([task]() { (*task)(); });
    taskSize++;
    // 在合适的时机，我们要添加线程
    if (mode == PoolMode::cached && curThreadSize < maxSize &&
        taskSize > curThreadSize) {
        cout << "create thread" << endl;
        this->AddThread();
    }
    notEmpty.notify_all();
    return task->get_future();
}
#endif  // THREADPOOL_TPLAST_H
